import type { Request, Response } from 'express';

import { spawn } from 'child_process';
import { z } from 'zod';

import Resp from '../../utils/response';

export const getBranchesSchema = z.object({
  url: z
    .string({
      invalid_type_error: 'Git仓库地址必须是字符串',
      required_error: 'Git仓库地址不能为空',
    })
    .min(1, 'Git仓库地址不能为空')
    .regex(
      /^(?:https?:\/\/|git@)[\w.-]+[/:][\w.-]+\/[\w.-]+(?:\.git)?$/,
      'Git仓库地址格式无效，请提供有效的Git仓库URL',
    ),
});

/**
 * 获取Git仓库分支列表
 * @param req Express请求对象
 * @param res Express响应对象
 * @returns Promise<Response | void>
 */
export async function getBranches(req: Request, res: Response): Promise<Response | void> {
  try {
    const { url } = req.query;

    // 获取分支列表，增加错误处理
    try {
      const branches = await getRemoteBranches(String(url));
      return Resp.success(
        res,
        {
          branches,
          total: branches.length,
        },
        '获取分支列表成功',
      );
    } catch (branchError) {
      console.error('获取分支列表失败:', branchError);

      return Resp.error(
        res,
        500,
        branchError instanceof Error ? branchError.message : '获取分支列表失败',
      );
    }
  } catch (error) {
    console.error('处理请求时发生错误:', error);
    return Resp.catch(res, error);
  }
}

/**
 * 执行git ls-remote命令获取远程分支列表
 * @param url Git仓库地址
 * @returns Promise<string[]> 分支名称数组
 */
function getRemoteBranches(url: string): Promise<string[]> {
  return new Promise((resolve, reject) => {
    const gitProcess = spawn('git', ['ls-remote', '--heads', url], {
      stdio: ['pipe', 'pipe', 'pipe'],
    });

    let stdout = '';
    let stderr = '';

    // 收集标准输出
    gitProcess.stdout.on('data', (data: Buffer) => {
      stdout += data.toString();
    });

    // 收集错误输出
    gitProcess.stderr.on('data', (data: Buffer) => {
      stderr += data.toString();
    });

    // 处理进程结束
    gitProcess.on('close', (code: number) => {
      if (code === 0) {
        try {
          // 解析git ls-remote输出，提取分支名称
          const branches = stdout
            .split('\n')
            .filter(line => line.trim() && line.includes('refs/heads/'))
            .map(line => {
              // 格式: <commit-hash>\trefs/heads/<branch-name>
              const parts = line.split('\t');
              if (parts.length >= 2) {
                return parts[1].replace('refs/heads/', '');
              }
              return null;
            })
            .filter((branch): branch is string => branch !== null)
            .sort(); // 按字母顺序排序

          resolve(branches);
        } catch (parseError) {
          reject(new Error('解析分支列表失败'));
        }
      } else {
        reject(new Error(`Git命令执行失败: ${stderr || '未知错误'}`));
      }
    });

    // 处理进程错误
    gitProcess.on('error', (error: Error) => {
      reject(new Error(`执行Git命令时发生错误: ${error.message}`));
    });

    // 设置超时
    const timeout = setTimeout(() => {
      gitProcess.kill('SIGTERM');
      reject(new Error('获取分支列表超时'));
    }, 30000); // 30秒超时

    gitProcess.on('close', () => {
      clearTimeout(timeout);
    });
  });
}
